﻿using System.IO;
using System.Net;
using System.Net.Mail;
using OpenPOP.POP3;
using OpenPOP.MIMEParser;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Marbles.Core.Web.Mail
{
    public class Mailbox
    {

        public string PopServer { get { return this._popserver; } }
        public int PopPort { get { return this._port; } }
        public string PopUsername { get { return this._popcredentials.UserName; } }
        public string PopPassword { get { return this._popcredentials.Password; } }
        public string SmtpServer { get { return this._smtpserver; } }
        public int SmtpPort { get { return this._smtpport; } }
        public string SmtpUsername { get { return this._smtpcredentials.UserName; } }
        public string SmtpPassword { get { return this._smtpcredentials.Password; } }

        private POPClient popClient = null;
        private string _popserver = string.Empty;
        private string _smtpserver = string.Empty;
        private int _port = 110;
        private int _smtpport = 25;
        private NetworkCredential _popcredentials = null;
        private NetworkCredential _smtpcredentials = null;

        public Mailbox(string PopServer, int Port, string Username, string Password, string SmtpServer, int SmtpPort, bool UsePopCredentialsOnSmtp)
        {
            popClient = new POPClient();
            this._popserver = PopServer;
            this._port = Port;
            this._popcredentials = new NetworkCredential(Username, Password);
            this._smtpcredentials = null;
            if (UsePopCredentialsOnSmtp) { this._smtpcredentials = this._popcredentials; }
            this._smtpserver = SmtpServer;
            this._smtpport = SmtpPort;
        }

        public Mailbox(string PopServer, int Port, string Username, string Password, string SmtpServer, int SmtpPort, string smtpUsername, string smtpPassword)
        {
            popClient = new POPClient();
            this._popserver = PopServer;
            this._port = Port;
            this._popcredentials = new NetworkCredential(Username, Password);
            this._smtpcredentials = new NetworkCredential(smtpUsername, smtpPassword);
            this._smtpserver = SmtpServer;
            this._smtpport = SmtpPort;
        }

        public Mailbox(string PopServer, int Port, NetworkCredential PopCredentials, string SmtpServer, int SmtpPort, NetworkCredential SmtpCredentials)
        {
            popClient = new POPClient();
            this._smtpserver = SmtpServer;
            this._smtpport = SmtpPort;
            this._popserver = PopServer;
            this._port = Port;
            this._popcredentials = PopCredentials;
            this._smtpcredentials = SmtpCredentials;
        }

        public Mailbox(string PopServer, int Port, NetworkCredential PopCredentials, string SmtpServer, int SmtpPort, bool UsePopCredentialsOnSmtp)
        {
            popClient = new POPClient();
            this._smtpserver = SmtpServer;
            this._smtpport = SmtpPort;
            this._popserver = PopServer;
            this._port = Port;
            this._popcredentials = PopCredentials;
            this._smtpcredentials = null;
            if (UsePopCredentialsOnSmtp) { this._smtpcredentials = this._popcredentials; }
        }

        public bool Connect()
        {
            if (!popClient.Connected)
            {
                try
                {
                    popClient.Connect(this._popserver, this._port);
                    popClient.Authenticate(this.PopUsername, this.PopPassword, AuthenticationMethod.TRYBOTH);
                }
                catch
                {
                    return false;
                }
            }
            return true;
        }

        public bool Disconnect()
        {
            if (popClient.Connected)
            {
                try
                {
                    popClient.Disconnect();
                }
                catch
                {
                    return false;
                }
            }
            return true;
        }

        public int GetMessageCount()
        {
            int total = -1;

            try
            {
                if (Connect())
                {
                    total = popClient.GetMessageCount();
                    this.Disconnect();
                }
            }
            catch
            {
                total = -1;
            }
            return total;
        }

        public List<Message> GetMessages(bool RetrieveHeaderOnly, bool KeepCopyOnServer)
        {
            List<Message> items = new List<Message>();
            if (Connect())
            {
                int Count = popClient.GetMessageCount();
                for (int i = Count; i >= 1; i -= 1)
                {
                    Message m = popClient.GetMessage(i, RetrieveHeaderOnly);
                    if (m != null)
                    {
                        items.Add(m);
                        if (!KeepCopyOnServer)
                        {
                            popClient.DeleteMessage(i);
                        }
                    }
                }

                Disconnect();
            }
            return items;
        }

        public Message GetMessage(int Index, bool RetrieveHeaderOnly, bool KeepCopyOnServer)
        {
            if (Connect())
            {
                Message m = popClient.GetMessage(Index, RetrieveHeaderOnly);

                if (m != null)
                {
                    if (!KeepCopyOnServer) { popClient.DeleteMessage(Index); }
                }

                Disconnect();
                return m;
            }

            return null;
        }

        public bool SendMessage(MailMessage m)
        {
            try
            {
                SmtpClient client = new SmtpClient(this._smtpserver, this._smtpport);
                client.Credentials = this._smtpcredentials;
                client.Send(m);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public bool SendMessage(Message m)
        {
            SmtpClient client = new SmtpClient(this._smtpserver, this._smtpport);
            client.Credentials = this._smtpcredentials;
            MailMessage msg = new MailMessage();
            msg.Sender = new MailAddress(m.FromEmail);
            msg.From = new MailAddress(m.FromEmail);
            msg.Subject = m.Subject;
            msg.Body = m.RawMessage;
            msg.IsBodyHtml = m.HTML;

            if (m.ReplyToEmail.Trim() != string.Empty) { msg.ReplyTo = new MailAddress(m.ReplyToEmail); }

            foreach (string s in m.TO)
            {
                if (s.Trim() != string.Empty) { msg.To.Add(new MailAddress(s.Trim())); }
            }

            foreach (string s in m.CC)
            {
                if (s.Trim() != string.Empty) { msg.CC.Add(new MailAddress(s.Trim())); }
            }

            foreach (string s in m.BCC)
            {
                if (s.Trim() != string.Empty) { msg.Bcc.Add(new MailAddress(s.Trim())); }
            }

            switch (m.ImportanceType)
            {
                case MessageImportanceType.HIGH: msg.Priority = MailPriority.High; break;
                case MessageImportanceType.LOW: msg.Priority = MailPriority.Low; break;
                case MessageImportanceType.NORMAL: msg.Priority = MailPriority.Normal; break;
            }

            if (m.HasAttachment)
            {
                for (int i = 0; i < m.Attachments.Count; i++)
                {
                    OpenPOP.MIMEParser.Attachment Attach = m.GetAttachment(i);
                    MemoryStream ms = new MemoryStream(Attach.RawBytes);
                    System.Net.Mail.Attachment sendAttach = new System.Net.Mail.Attachment(ms, Attach.ContentFileName, Attach.ContentType);
                    msg.Attachments.Add(sendAttach);
                }
            }

            try
            {
                client.Send(msg);
            }
            catch
            {
                return false;
            }

            return true;
        }
    }
}

